#include <stdio.h>
#include <stm32f10x_gpio.h>
#include <stm32f10x_rcc.h>
#include <stm32f10x_adc.h>
#include <stm32f10x_tim.h>
#include <Config.h>
#include <LCD_driver.h>
#include <ADC_STM32.h>

unsigned int flag_adc_alarm_maxmin = 0;//1: alarm min;//2: alarm max
static unsigned int adc_alarm_min = 0;
static unsigned int adc_alarm_max = 100;
static unsigned int delay = 1;
static unsigned int delay_tmp = 0;
static unsigned int flag_alarm = 0;
/*
 *
 */
void ADC1_configuration(void) {
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1
			| RCC_APB2Periph_AFIO, ENABLE);
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfChannel = ADC_Channel_1;
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_1Cycles5);
	ADC_Init(ADC1, &ADC_InitStructure);
	ADC_Cmd(ADC1, ENABLE);
}

/*
 *
 */
uint16_t ADC1_ReadInput(void) {
	uint16_t temp = 0;
	if (flag_alarm == 0) {
		ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	}
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET)
		;
	ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
	temp = ADC_GetConversionValue(ADC1);
	if (flag_alarm == 0) {
		ADC_SoftwareStartConvCmd(ADC1, DISABLE);
	}
	return temp * 100 / 4095;
}

/*********************************************************************************
 * boundary >< 0: high (max) level
 * boundary = 0: low (min) level
 *
 *********************************************************************************/
void ADC1_Set_alarm_level(uint8_t boundary, unsigned int level) {
	if (boundary == 0) {
		if ((level > 99) || (level >= adc_alarm_max)) {
			OUTPUT_USARTTerm;
			puts("level is incorrect, auto set adc_alarm_min to 0\r\n");
			adc_alarm_min = 0;
		} else {
			adc_alarm_min = level;
		}
	} else {
		if (((level < 1) && (level > 100)) || (level <= adc_alarm_min)) {
			OUTPUT_USARTTerm;
			puts("level is incorrect, auto set adc_alarm_max to 100\r\n");
			adc_alarm_max = 100;
		} else {
			adc_alarm_max = level;
		}
	}
}

/*********************************************************************************
 * boundary >< 0: high (max) level
 * boundary = 0: low (min) level
 *
 *********************************************************************************/
uint8_t ADC1_Get_alarm_level(uint8_t boundary) {
	if (boundary == 0) {
		return adc_alarm_min;
	} else {
		return adc_alarm_max;
	}
}

/*
 * boundary >< 0: high (max) level
 * boundary = 0: low (min) level
 */
void ADC1_alarm_trig(uint8_t boundary) {
	if (boundary == 0) {
		LCD_ClearDisplay();
		OUTPUT_LCD;
		puts("ADC ALARM !!!");
		LCD_GotoXY(0, 1);
		OUTPUT_LCD;
		puts("UNDER LOW LEVEL");
		OUTPUT_USARTTerm;
		puts("ADC ALARM !!! -> UNDER LOW LEVEL\r\n");
	} else {
		LCD_ClearDisplay();
		OUTPUT_LCD;
		puts("ADC ALARM !!!");
		LCD_GotoXY(0, 1);
		OUTPUT_LCD;
		puts("OVER HIGH LEVEL");
		OUTPUT_USARTTerm;
		puts("ADC ALARM !!! -> OVER HIGH LEVEL\r\n");
	}

}

/*
 *
 */
void ADC1_active_Alarm(unsigned int delay_check) {
	ADC_SoftwareStartConvCmd(ADC1, DISABLE);
	Switch_timer_ADC_IRQ(DISABLE);
	if (delay_check == 0) {
		OUTPUT_USARTTerm;
		puts("ADC alarm off\r\n");
	} else {
		if (delay_check > 100) {
			OUTPUT_USARTTerm;
			puts("delay is out of range, auto set adc_alarm_delay to 100\r\n");
			delay = 100;
		} else {
			delay = delay_check;
		}
		flag_alarm = 1;
		delay_tmp = 0;
		ADC_SoftwareStartConvCmd(ADC1, ENABLE);
		Switch_timer_ADC_IRQ(ENABLE);
		OUTPUT_USARTTerm;
		puts("ADC alarm activated\r\n");
	}
}

void TIM5_IRQHandler(void) {
	if (TIM_GetITStatus(TIM5, TIM_IT_Update) == SET) {
		if (delay_tmp < delay) {
			delay_tmp++;
		} else {
			delay_tmp = 0;
			unsigned int level = ADC_GetConversionValue(ADC1) * 100 / 4095;
			if (level < adc_alarm_min) {
				flag_adc_alarm_maxmin = 1;
			} else if (level > adc_alarm_max) {
				flag_adc_alarm_maxmin = 2;
			}
		}
		TIM_ClearITPendingBit(TIM5, TIM_IT_Update);
	}
}
